{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 打印所有单行变量\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "python\n"
     ]
    }
   ],
   "source": [
    "def foo(str):  # 定义函数\n",
    "    print(str)\n",
    "    return\n",
    "\n",
    "foo(\"python\")  # 调用函数\n",
    "foo            # --> 函数对象指向foo变量\n",
    "foo = 10       # 重定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### return语句\n",
    "return语句用于`退出函数`，选择性地向调用方`返回`一个表达式。不带参数值的return语句返回None。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "函数内 :  30\n",
      "返回值 :  30\n"
     ]
    }
   ],
   "source": [
    "def sum( arg1, arg2 ):\n",
    "    total = arg1 + arg2\n",
    "    print (\"函数内 : \", total)\n",
    "    return total\n",
    "\n",
    "total = sum( 10, 20 )\n",
    "print (\"返回值 : \", total)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数的属性\n",
    "\n",
    "#### `__doc__`\n",
    "\n",
    "前面用dir()查看属性和方法时，里面有个`__doc__`属性，便于阅读函数的使用方法和注释。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'this is my function'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function myfun in module __main__:\n",
      "\n",
      "myfun()\n",
      "    this is my function\n",
      "\n"
     ]
    }
   ],
   "source": [
    "\n",
    "def myfun():\n",
    "    'this is my function'  # 本质就是字符串，可以用三引号\n",
    "    pass\n",
    "\n",
    "myfun.__doc__  # -->\n",
    "help(myfun)    # -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 增加函数属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "myfun.newnum = 10       # 增加一个newnum函数属性\n",
    "\n",
    "myfun.newnum            # -->\n",
    "'newnum' in dir(myfun)  # -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面属性用双下划线开始和结束，这类属性可以称之为**特殊属性**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'myfun'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "ename": "AttributeError",
     "evalue": "'function' object has no attribute '__getname__'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-15-279966f84c2c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mmyfun\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m     \u001b[0;31m# --> 在创建函数时就已定义好\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mmyfun\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__getname__\u001b[0m  \u001b[0;31m# >_< 没有定义的属性不能调用\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'function' object has no attribute '__getname__'"
     ]
    }
   ],
   "source": [
    "myfun.__name__     # --> 在创建函数时就已定义好\n",
    "myfun.__getname__  # >_< 没有定义的属性不能调用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 参数\n",
    "> 在定义函数的时候，函数名后面的括号里如果有变量，它们通常被称为“形参”。  \n",
    "> 调用函数的时候，给函数提供的值叫做“实参”，或者“参数”。  \n",
    "> 可以将形参当作一个停车位，而将实参当作一辆汽车。 就像一个停车位可以在不同时间停放不同的汽车一样。  \n",
    "\n",
    "以下是调用函数时可使用的正式参数类型：\n",
    "- 必需参数\n",
    "- 关键字参数\n",
    "- 默认参数\n",
    "- 不定长参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 必需参数\n",
    "必需参数会以一一对应的顺序传入函数，调用时的数量必须和声明时的一样。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "名字:  wanli\n",
      "年龄:  26\n"
     ]
    }
   ],
   "source": [
    "# 定义函数\n",
    "def myfun(name, age):\n",
    "    \"打印任何传入的字符串\"    # __doc__属性\n",
    "    print(\"名字: \", name)  # 结尾分号可用可不用\n",
    "    print(\"年龄: \", age)\n",
    "\n",
    "# 调用myfun函数\n",
    "myfun(\"wanli\", 26)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "myfun() missing 1 required positional argument: 'age'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-18-9fb0ee3c9cbf>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmyfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'wanli'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: myfun() missing 1 required positional argument: 'age'"
     ]
    }
   ],
   "source": [
    "myfun('wanli')  # >_< 缺少参数会报错"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 关键字参数\n",
    "\n",
    "使用关键字参数允许函数调用时参数的顺序与声明时不一致，因为 Python 解释器能够用参数名匹配参数值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "名字:  wanli\n",
      "年龄:  26\n"
     ]
    }
   ],
   "source": [
    "def myfun(name, age):\n",
    "    print(\"名字: \", name)\n",
    "    print(\"年龄: \", age)\n",
    "\n",
    "myfun(age=26, name=\"wanli\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 默认参数\n",
    "\n",
    "调用函数时，如果没有传递参数，则会使用默认参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "名字:  wanli\n",
      "年龄:  26\n"
     ]
    }
   ],
   "source": [
    "def myfun(name, age=26):\n",
    "    print(\"名字: \", name)\n",
    "    print(\"年龄: \", age)\n",
    "\n",
    "myfun(\"wanli\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 不定长参数\n",
    "\n",
    "##### *args\n",
    "    def foo(*args):\n",
    "        pass\n",
    "\n",
    "用`*arg`形式收集参数会存放所有未命名的变量参数并返回一个元组。如果在函数调用时没有指定参数，它就是一个空元组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 'python', 3)\n",
      "<class 'tuple'>\n"
     ]
    }
   ],
   "source": [
    "def foo(*args):\n",
    "    print(args)\n",
    "\n",
    "foo(1,'python',3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### **kargs\n",
    "\n",
    "    def foo(**kargs):\n",
    "        pass\n",
    "\n",
    "用`**kargs`的形式收集参数，会得到dict类型的数据，但是，需要在传参数的时候说明“键”和“值”，因为在字典中是以键值对形式出现的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'b': 2, 'a': 1, 'c': 3}\n"
     ]
    }
   ],
   "source": [
    "def foo(**kargs):\n",
    "    print(kargs)\n",
    "\n",
    "foo(a=1,b=2,c=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 多种类型参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def foo(x,y,z,*args,**kargs):\n",
    "    print(x)\n",
    "    print(y)\n",
    "    print(z)\n",
    "    print(args)\n",
    "    print(kargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "wanli\n",
      "2\n",
      "python\n",
      "()\n",
      "{}\n"
     ]
    }
   ],
   "source": [
    "foo('wanli',2,\"python\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "(4, 5)\n",
      "{}\n"
     ]
    }
   ],
   "source": [
    "foo(1,2,3,4,5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "(4, 5)\n",
      "{'name': 'wanli'}\n"
     ]
    }
   ],
   "source": [
    "foo(1,2,3,4,5,name=\"wanli\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 解包实参调用函数\n",
    "前面说到传递任意数量的实参时会将它们打包进一个元组或字典，当然有打包也就有解包（unpacking）。通过单星号和双星号对List、Tuple和Dictionary进行解包："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n",
      "15\n"
     ]
    }
   ],
   "source": [
    "def fun(a, b, c):\n",
    "    print(a+b+c)\n",
    "\n",
    "x = [1, 2, 3]\n",
    "d = {'a':4, 'b':5, 'c':6}\n",
    "\n",
    "fun(*x)   # --> *解包list和tuple\n",
    "fun(**d)  # --> **解包dict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 递归\n",
    "> 递归（recursion），又译为递回，在数学与计算机科学中，是指在函数的定义中使用函数自身的方法。\n",
    "\n",
    "根据斐波那契数列的定义，可以直接写成这样的斐波那契数列递归函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入正整数:4\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def fib(n):\n",
    "    \"\"\"\n",
    "    This is Fibonacci by Recursion.\n",
    "    \"\"\"\n",
    "    if n == 0:\n",
    "        return 0\n",
    "    elif n == 1:\n",
    "        return 1\n",
    "    else:\n",
    "        return fib(n-1) + fib(n-2)\n",
    "\n",
    "n = int(input('输入正整数:'))\n",
    "fib(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "解析：  \n",
    "当n = 4时：\n",
    "```\n",
    "fib(4) = fib(3)        +     fib(2)\n",
    "             ↓                   ↓\n",
    "      fib(2) + fib(1)     fib(1) + fib(0)\n",
    "          ↓\n",
    "   fib(1) + fib(0)\n",
    "\n",
    "```\n",
    "\n",
    "相当于fib(4) = 3*fib(1) + 2*fib(0) = 3\n",
    "\n",
    "> 上面的代码每次递回下一级函数，都要判断一次判断一次if和elif  \n",
    "> 用递归函数要小心，因为很容易陷入死循环"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  函数式编程\n",
    "\n",
    "Python是支持多种范型的语言，可以进行所谓函数式编程，其突出体现在有这么几个函数：filter、map、reduce、lambda、yield。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 匿名函数lambda\n",
    "\n",
    "- 在lambda后面直接跟变量\n",
    "- 变量后面是冒号\n",
    "- 冒号后面是表达式，表达式计算结果就是本函数的返回值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "(1, 6)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "func1 = lambda x: x * x      # <=> def func1(x): return(x * x)\n",
    "func2 = lambda x: x % 2      # <=> def func2(x): return(x % 2)\n",
    "func3 = lambda x, y: (x, y)  # <=> def func3(x, y): return (x, y)\n",
    "\n",
    "func1(3)\n",
    "func2(5)\n",
    "func3(1, 6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### map(function, iterable[,iterable2])\n",
    " \n",
    "1. iterable的数量必须和function的参数一致\n",
    "2. 按顺序一一对应从可迭代对象传入参数\n",
    "3. 函数返回的值是一个以list的形式的map对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<map at 0x7f47cc520dd8>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[14, 17, 20, 15, 6]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[14, 17, 20, 15, 6]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst1 = [1, 2, 3, 4, 5]\n",
    "lst2 = [6, 7, 8, 9, 0]\n",
    "lst3 = [7, 8, 9, 2, 1]\n",
    "\n",
    "x = map(lambda x,y,z: x+y+z, lst1, lst2, lst3)\n",
    "x        # --> map对象\n",
    "list(x)  # -->\n",
    "\n",
    "y = [x+y+z for x,y,z in zip(lst1, lst2, lst3)]\n",
    "y        # -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### reduce"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "120"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from functools import reduce\n",
    "reduce(lambda x,y: x*y, [1, 2, 3, 4, 5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### filter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<filter at 0x7f47cc5c74a8>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[1, 2]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[1, 2]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numbers = range(-2,3)\n",
    "f = filter(lambda x: x>0, numbers)\n",
    "\n",
    "f        # -->\n",
    "list(f)  # -->\n",
    "[x for x in numbers if x>0]  # -->"
   ]
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4rc1"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "toc_cell": false,
   "toc_position": {
    "height": "839px",
    "left": "0px",
    "right": "1608px",
    "top": "107px",
    "width": "312px"
   },
   "toc_section_display": "block",
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": "15",
    "lenType": "10",
    "lenVar": "60"
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
